unit uMainForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,

  GlScene, GlObjects, GlCadencer, GLWin32Viewer, GLRenderContextInfo, GlWindowsFont, GlHudObjects,
  GlMaterial,
  VectorGeometry,

  uSimplePanel, uSimpleListBox;

type
  TfrmMain = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    {Main Objects}
    fGlScene: TGlScene;
    fCadencer: TGLCadencer;
    fViewer: TGLSceneViewer;
    fCamera: TGlCamera;
    fMainDummy: TGlDummyCube;
    fFpsTimer: Single;
    fMatLib: TGlMaterialLibrary;
    fMouseOldPos: TVector;
    fMousePressed: Boolean;

    {Text Objects}
    fWinFont: TGLWindowsBitmapFont;
    fHudText: TGLHUDText;
    fBack: TGlHudSprite;

    {Panel}
    fPanel: TSimplePanel;
    fSizing: TNCSizing;
    fStartPosSizing: TVector;
    fDoSizing: Boolean;

    {Skins}
    fSkinsList: TSimpleListBox;
  public
    Procedure InitMaterials;
    Procedure InitFont;
    Procedure InitObjects;
    Procedure AttachMaterials;

    Procedure UpdateSizing(MPos: TVector; DeltaPos: TVector);
    Procedure UpdateMoving(MPos: TVector; DeltaPos: TVector);
    
    Procedure OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
  end;

var
  frmMain: TfrmMain;

implementation
uses
  GlKeyboard,
  uDemoInit;
{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  fFpsTimer := 0;
  CreateDemo(self, fGlScene, fCadencer, fViewer);
  
  fCamera := TGlCamera.CreateAsChild(fGlScene.Objects);
  with fCamera do
  begin
    Position.SetPoint(0, 0, 5);
    Direction.SetVector(0, 0, -1);
    Up.SetVector(0, 1, 0);
    CameraStyle := csOrthogonal;
    SceneScale := 0.1;
  end;

  fMainDummy := TGLDummyCube.CreateAsChild(fGlScene.Objects);
  fMainDummy.ObjectsSorting := osNone;

  fViewer.Camera := fCamera;
  fCadencer.OnProgress := OnCadencerProgress;
  fCadencer.Enabled := true;
  fMatLib := TGlMaterialLibrary.Create(self);

  InitFont;
  InitObjects;
  InitMaterials;
  AttachMaterials;
end;

Procedure TfrmMain.InitFont;
begin
  fWinFont := TGLWindowsBitmapFont.Create(self);
  fWinFont.Font.Name := 'Arial';
end;

Procedure TfrmMain.InitObjects;
begin
  fBack := TGlHudSprite.CreateAsChild(fMainDummy);

  fHudText := TGLHUDText.CreateAsChild(fMainDummy);
  with fHudText do
  begin
    BitmapFont := fWinFont;
    Text := 'Lampogolovii presents ''Simple Panel Demo''';
    Position.SetPoint(790, 580, 0);
    Alignment := taRightJustify;
  end;

  fPanel := TSimplePanel.CreateAsChild(fMainDummy);
  fPanel.Material.MaterialLibrary := fMatLib;
  fPanel.Position.SetPoint(600, 200, 0);
  fPanel.Width := 200;
  fPanel.Height := 200;
end;

Procedure TfrmMain.AttachMaterials;
begin
  with fBack do
  begin
    Material.MaterialLibrary := fMatLib;
    Material.LibMaterialName := 'back';
    Width := Material.GetActualPrimaryTexture.Image.Width;
    Height := Material.GetActualPrimaryTexture.Image.Height;
    Position.SetPoint(Width / 2, Height / 2, 0);
  end;

  fPanel.Material.LibMaterialName := 'white';
end;

Procedure TfrmMain.InitMaterials;
const
  SkinsNames: array [1..8] of String = ('white', 'blue', 'shadow', 'transparent', 'marene', 'orange', 'green', 'bloody');
var
  i: integer;
begin
  AddMaterials(fMatLib, str_ImagesFolder + '\SimplePanel\', ['back_panel.png', 'front_panel.png', 'selection.png'],
                                               ['back_panel', 'front_panel', 'selection_panel']);

  fSkinsList := TSimpleListBox.CreateAsChild(fMainDummy, fMatLib, fWinFont);
  fSkinsList.Position.X := 150;
  fSkinsList.Position.Y := 300;

  for i := 1 to 8 do
  begin
    AddMaterial(fMatLib, str_ImagesFolder + '\SimplePanel\' + SkinsNames[i] + '.png', SkinsNames[i]);
    fSkinsList.AddItemText(inttostr(i) + '. ' + SkinsNames[i]);
  end;


  AddMaterial(fMatLib, str_ImagesFolder + '\SimplePanel\back.jpg', 'back');
end;

Procedure TfrmMain.UpdateSizing(MPos: TVector; DeltaPos: TVector);
begin
  if not fDoSizing then
  begin
    fSizing := fPanel.NCHitTest(MPos);
    if (fSizing = cs_Left) or (fSizing = cs_Right) then
      fViewer.Cursor := crSizeWE
    else if (fSizing = cs_Top) or (fSizing = cs_Bottom) then
      fViewer.Cursor := crSizeNS
    else
      fViewer.Cursor := crDefault;
  end
  else
  begin
    if fSizing = cs_Left then
    begin
      fPanel.Width := fPanel.Width - Trunc(DeltaPos[0] / 2) * 2;
      fPanel.Position.X := fPanel.Position.X + Trunc(DeltaPos[0] / 2);
    end
    else if fSizing = cs_Right then
    begin
      fPanel.Width := fPanel.Width + Trunc(DeltaPos[0] / 2) * 2;
      fPanel.Position.X := fPanel.Position.X + Trunc(DeltaPos[0] / 2);
    end
    else if fSizing = cs_Top then
    begin
      fPanel.Height := fPanel.Height - Trunc(DeltaPos[1] / 2) * 2;
      fPanel.Position.Y := fPanel.Position.Y + Trunc(DeltaPos[1] / 2);
    end
    else if fSizing = cs_Bottom then
    begin
      fPanel.Height := fPanel.Height + Trunc(DeltaPos[1] / 2) * 2;
      fPanel.Position.Y := fPanel.Position.Y + Trunc(DeltaPos[1] / 2);
    end;
  end;
end;

Procedure TfrmMain.UpdateMoving(MPos: TVector; DeltaPos: TVector);
begin
  if fMousePressed and fPanel.IsHit(MPos) and not fDoSizing then
    with fPanel.Position do
    begin
      SetPoint(x + DeltaPos[0], y + DeltaPos[1], 0);

      if x <= 380 then
        x := 380
      else if x > 700 then
        x := 700;

      if y <= 100 then
        y := 100
      else if y > 500 then
        y := 500;
    end;
end;

Procedure TfrmMain.OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
var
  MPos: TPoint;
  MVec, DeltaVec: TVector;
  Text: String;
begin
  fViewer.Invalidate;

  GetCursorPos(MPos);
  MPos := fViewer.ScreenToClient(MPos);
  fSkinsList.SetMousePosition(MPos.x, MPos.y);

  MVec := VectorMake(MPos.x, MPos.y, 0);
  DeltaVec := VectorMake(MPos.x - fMouseOldPos[0], MPos.y - fMouseOldPos[1], 0);
  
  UpdateSizing(MVec, DeltaVec);
  UpdateMoving(MVec, DeltaVec);

  if IsKeyDown(vk_LButton) and not fMousePressed then
  begin
    with fSkinsList do
      if GetIndexByMouse <> -1 then
      begin
        Text := GetItemByMouse.Text;
        Text := Copy(Text, 4, Length(Text) - 3);
        fPanel.Material.LibMaterialName := Text;
      end;

      if fSizing <> cs_None then
      begin
        fDoSizing := true;
        fStartPosSizing := MVec;
      end;
   end;

  if (not IsKeyDown(vk_LButton)) and fDoSizing then
  begin
    fDoSizing := false;
    fSizing := cs_None;
  end;
  
  fMouseOldPos := VectorMake(MPos.x, MPos.y, 0);
  fMousePressed := IsKeyDown(vk_LButton);
end;

end.
